package edu.njit.hz278.core.web;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;

/**
 * 
 * @author Rivers Zhang
 *
 */
public class BindingResultAndValidityInvoker extends AbstractInvoker {

	private boolean[] paramForceValid;

	public BindingResultAndValidityInvoker(Object target, Method method,
			String[] paramNames, boolean[] paramForceValid) {
		super(target, method, paramNames);
		this.paramForceValid = paramForceValid;
	}

	@Override
	public void perform(HttpServletRequest req, HttpServletResponse resp)
			throws JsonParseException, JsonMappingException,
			InstantiationException, IllegalAccessException, IOException,
			IllegalArgumentException, InvocationTargetException {
		
		Object[] args = new Object[paramLen];
		ModelView mv = null;
		BindingResult br = new BindingResult();

		/**
		 * if there's anything invalid regarding the arguments. Initially, true.
		 */
		boolean forceValidHolds = true;

		// parse the arguments from @req
		for (int i = 0; i < paramLen; ++i) {

			Class<?> type = paramTypes[i];

			if (type.isPrimitive() || type == String.class)
				// if type is primitive or string
				args[i] = getPrimitiveValue(type,
						req.getParameter(paramNames[i]));
			else if (type.isArray()) { // if it is an array
				if (type.getComponentType().isPrimitive())
					args[i] = getPrimitiveValues(type.getComponentType(),
							req.getParameterValues(paramNames[i]));
				else
					args[i] = createBeans(type.getComponentType(),
							req.getParameter(paramNames[i]));
			} else if (type == ModelView.class)
				args[i] = (mv == null) ? (mv = new ModelView()) : mv;
			else if (type == HttpServletRequest.class)
				args[i] = req;
			else if (type == HttpServletResponse.class)
				args[i] = resp;
			else if (type == BindingResult.class)
				args[i] = br;
			else {
				args[i] = createBean(type, req.getParameter(paramNames[i]));
				boolean valid = br.validate(paramNames[i], args[i]);
				if (paramForceValid[i])
					forceValidHolds = forceValidHolds && valid;
			}
		}

		// actually call the method
		Object ret = forceValidHolds ? method.invoke(target, args) : br
				.wrapErrors();

		writer.write(req, resp, ret, mv);
	}

}
